﻿using Asion.Dapper.SqlBuilder.Condition;
using Dapper;
using Microsoft.Data.SqlClient;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Asion.Dapper
{

    public class SimpleCrudRepository<TEntity> : BaseRepository, ICrudRepository<TEntity> where TEntity : class, IEntity
    {
        public SimpleCrudRepository() : base()
        {

        }


        public int Insert(TEntity model, List<string> excludes = null)
        {
            int? result;
            using (var connection = this.GetDbConnection<TEntity>())
            {
                result = connection.Insert<TEntity>(model, excludes: excludes);
            }
            return result ?? 0;
        }


        public int BatchInsert(List<TEntity> models, List<string> excludeColumns = null, int singleBatchCount = DapperConfiguration.batch_insert_count, int delayMaxCount = 5000, int delayDefaultSleepMillSeconds = 100, int delayOverCountSleepMillSeconds = 500)
        {
            if (models == null || !models.Any())
                return 0;


            //插入使用队列，加速gc的释放
            var queue = new Queue<TEntity>();

            models.ToList().ForEach(a =>
            {
                queue.Enqueue(a);
            });
            //数据较多的情况下，为了防止给数据库造成太大压力，需休眠下
            int sleepMillSeconds = 100;
            if (queue.Count() >= delayMaxCount)
            {
                sleepMillSeconds = 500;
            }

            var curs = new List<TEntity>();
            var pageIndex = 1;
            var result = 0;
            while (queue.Any())
            {

                var temp = queue.Dequeue();
                if (temp != null)
                    curs.Add(temp);
                //达到了insertPageCount 才开始插入
                if (curs.Count() == singleBatchCount)
                {
                    //调用底层开始插入
                    using (var connection = this.GetDbConnection<TEntity>())
                    {
                        result += connection.BatchInsert<TEntity>(curs, excludeColumns: excludeColumns);
                    }
                    //将临时数据清除
                    curs.Clear();
                    //第一次不延迟，最后一次也不延迟
                    if (pageIndex != 1)
                        Thread.Sleep(sleepMillSeconds);
                    pageIndex++;
                }
            }
            if (curs.Any())
            {
                using (var connection = this.GetDbConnection<TEntity>())
                {
                    result += connection.BatchInsert<TEntity>(curs, excludeColumns: excludeColumns);
                }
            }

            return result;

        }





        public bool Delete(IWhere where)
        {
            int? result;
            using (var connection = this.GetDbConnection<TEntity>())
            {
                result = connection.Delete<TEntity>(where);
            }
            return result > 0 ? true : false;
        }

        public bool DeleteList(IWhere where)
        {
            int? result;
            using (var connection = this.GetDbConnection<TEntity>())
            {
                result = connection.DeleteList<TEntity>(where);
            }
            return result > 0 ? true : false;
        }



        public bool Update(TEntity model, IUpdateWhere where, List<string> excludes = null)
        {
            int result;
            using (var connection = this.GetDbConnection<TEntity>())
            {
                result = connection.Update<TEntity>(model, where, excludes: excludes);
            }
            return result > 0 ? true : false;
        }

        public int BatchUpdate(List<TEntity> models, string[] updateColmuns, string updateColmunsWhere, IWhere where, int singleBatchCount = DapperConfiguration.batch_update_count, int delayMaxCount = 5000, int delayDefaultSleepMillSeconds = 100, int delayOverCountSleepMillSeconds = 500)
        {
            if (models == null || !models.Any())
                return 0;


            //插入使用队列，加速gc的释放
            var queue = new Queue<TEntity>();

            models.ToList().ForEach(a =>
            {
                queue.Enqueue(a);
            });
            //数据较多的情况下，为了防止给数据库造成太大压力，需休眠下
            int sleepMillSeconds = 100;
            if (queue.Count() >= delayMaxCount)
            {
                sleepMillSeconds = 500;
            }

            var curs = new List<TEntity>();
            var pageIndex = 1;
            var result = 0;
            while (queue.Any())
            {

                var temp = queue.Dequeue();
                if (temp != null)
                    curs.Add(temp);
                //达到了insertPageCount 才开始插入
                if (curs.Count() == singleBatchCount)
                {
                    //调用底层开始插入
                    using (var connection = this.GetDbConnection<TEntity>())
                    {
                        result += connection.BatchUpdate<TEntity>(models, updateColmuns, updateColmunsWhere, where);
                    }
                    //将临时数据清除
                    curs.Clear();
                    //第一次不延迟，最后一次也不延迟
                    if (pageIndex != 1)
                        Thread.Sleep(sleepMillSeconds);
                    pageIndex++;
                }
            }
            if (curs.Any())
            {
                using (var connection = this.GetDbConnection<TEntity>())
                {
                    result += connection.BatchUpdate<TEntity>(models, updateColmuns, updateColmunsWhere, where);
                }
            }
            return result;
        }


        public int Update(IUpdateColumn column, IWhere where)
        {
            int result;
            using (var connection = this.GetDbConnection<TEntity>())
            {
                result = connection.Update<TEntity>(column, where);
            }
            return result;
        }

        public SaveReponse Save(TEntity entity, IUpdateWhere where, SaveExcludeRequest excludeRequest)
        {
            using (var connection = this.GetDbConnection<TEntity>())
            {
                return connection.Save<TEntity>(entity, where, excludeRequest: excludeRequest);
            }

        }

        public BatchSaveReponse BatchSave(BatchSaveRequest<TEntity> request)
        {
            using (var connection = this.GetDbConnection<TEntity>())
            {
                return connection.BatchSave<TEntity>(request);
            }

        }

        public int IncreaseCount(string column, int value, IWhere where)
        {
            int result;
            using (var connection = this.GetDbConnection<TEntity>())
            {
                result = connection.IncreaseCount<TEntity>(column, value, where);
            }
            return result;
        }

        public int DecreaseCount(string column, int value, IWhere where)
        {
            int result;
            using (var connection = this.GetDbConnection<TEntity>())
            {
                result = connection.DecreaseCount<TEntity>(column, value, where);
            }
            return result;
        }



        public TEntity Get(IWhere where, IOrderBy order = null)
        {
            TEntity result;
            using (var connection = this.GetDbConnection<TEntity>())
            {
                result = connection.Get<TEntity>(where, order);
            }
            return result;
        }


        public TEntity Get(ISelectColumn column, IWhere where, IOrderBy order = null)
        {
            TEntity result;
            using (var connection = this.GetDbConnection<TEntity>())
            {
                result = connection.Get<TEntity>(column, where, order);
            }
            return result;
        }

        public IEnumerable<TEntity> GetList(IWhere where, IOrderBy order = null, IGroupColumn group = null)
        {
            IEnumerable<TEntity> result;
            using (var connection = this.GetDbConnection<TEntity>())
            {
                result = connection.GetList<TEntity>(where, order: order, group: group);
            }
            return result;
        }

        public IEnumerable<TEntity> GetList(ISelectColumn column, IWhere where, IOrderBy order = null, IGroupColumn group = null)
        {
            IEnumerable<TEntity> result;
            using (var connection = this.GetDbConnection<TEntity>())
            {
                result = connection.GetList<TEntity>(column, where, order: order, group: group);
            }
            return result;
        }


        public IEnumerable<TEntity> GetTopList(int topCount, ISelectColumn column, IWhere where, IOrderBy order = null, IGroupColumn group = null)
        {
            IEnumerable<TEntity> result;
            using (var connection = this.GetDbConnection<TEntity>())
            {
                result = connection.GetTopList<TEntity>(topCount, column, where, order: order, group: group);
            }
            return result;
        }

        public PageReponse<TEntity> GetPageList(ISelectColumn column, IWhere where, int pageNumber = 1, int rowsPerPage = DapperConfiguration.default_rows_page, IOrderBy order = null)
        {
            PageReponse<TEntity> result;
            using (var connection = this.GetDbConnection<TEntity>())
            {
                result = connection.GetPageList<TEntity>(column, where, pageNumber: pageNumber, rowsPerPage: rowsPerPage, order: order);
            }
            return result;
        }

        public int RecordCount(IWhere where)
        {
            int result;
            using (var connection = this.GetDbConnection<TEntity>())
            {
                result = connection.RecordCount<TEntity>(where);
            }
            return result;
        }


        public bool Exist(IWhere where)
        {
            bool result;
            using (var connection = this.GetDbConnection<TEntity>())
            {
                result = connection.Exist<TEntity>(where) > 0;
            }
            return result;
        }


        /// <summary>
        /// 连接查询
        /// </summary>
        /// <typeparam name="TFirst"></typeparam>
        /// <typeparam name="TSecond"></typeparam>
        /// <typeparam name="TReturn"></typeparam>
        /// <param name="sql"></param>
        /// <param name="map"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public IEnumerable<TReturn> Query<TFirst, TSecond, TReturn>(string sql, object param, Func<TFirst, TSecond, TReturn> map)
        {
            IEnumerable<TReturn> result;
            using (var connection = this.GetDbConnection<TEntity>())
            {
                result = connection.Query<TFirst, TSecond, TReturn>(sql, map, param);
            }
            return result;
        }

        public Tuple<TReturn1, TReturn2> QueryMult<TReturn1, TReturn2>(string[] sqls, object param)
        {
            var resultA = default(TReturn1);
            var resultB = default(TReturn2);
            var sql = string.Join(";", sqls);
            using (var connection = this.GetDbConnection<TEntity>())
            {
                var gird = connection.QueryMultiple(sql, param);
                resultA = gird.ReadFirstOrDefault<TReturn1>(); //ReadFirstOrDefault value 当查不到数据的时候会返回null
                resultB = gird.ReadFirstOrDefault<TReturn2>();
            }
            return new Tuple<TReturn1, TReturn2>(resultA, resultB);

        }

        public Tuple<TReturn1, TReturn2, TReturn3> QueryMult<TReturn1, TReturn2, TReturn3>(string[] sqls, object param)
        {
            var resultA = default(TReturn1);
            var resultB = default(TReturn2);
            var resultC = default(TReturn3);
            var sql = string.Join(";", sqls);
            using (var connection = this.GetDbConnection<TEntity>())
            {
                var gird = connection.QueryMultiple(sql, param);
                resultA = gird.ReadFirstOrDefault<TReturn1>();
                resultB = gird.ReadFirstOrDefault<TReturn2>();
                resultC = gird.ReadFirstOrDefault<TReturn3>();
            }
            return new Tuple<TReturn1, TReturn2, TReturn3>(resultA, resultB, resultC);
        }
    }



}
